/*
 *  Sea.h
 *  Pirates!
 *
 *  Created by Alan Dorin on 20/03/10.
 *  Copyright 2007 __MyCompanyName__. All rights reserved.
 *
 */
 
#ifndef _SEA_H_
#define _SEA_H_

#include "Globals.h"
#include "SimpleVector.h"

class GridCell;
class Gold;
class AIController;
class Ship;

#include <iostream>

class Sea
{
	protected:
		long cellArrayDimension;						// dimensions of the sea (in grid cells)
		long numShips;									// number of ships in the Sea (constant value)
		long numGolds;									// total number of gold deposits in the Sea
		long numRocks;									// total number of rocks in the Sea
		
		GridCell**		cellArray; 						// 2D array of cells which hold the ships in the grid
        GridCell**		cellArrayBuffer;				// 2D array of cells which hold the ships in the grid (at *next* time step)
        Ship*			shipArray;						// the array of ships roaming the cell array
		Ship*			shipArrayBuffer;				// the array of ships roaming the cell array (at *next* time step)
		long*			randomShipIndexArray;			// an array to hold ship indices into the shipArray in a randomised order
		
		Gold*			goldArray;						// the array of gold distributed around the cell array
														// no buffer is needed for the goldArray as this does not change between timesteps

	public:
		Sea();
		Sea(long newCellArrayDimension, long newNumShips);	// construct with fresh ships
		Sea(const Sea& src);
		~Sea(void);
		
		void setShipPositionBuffer(long shipArrayIndex, long shipXPos, long shipYPos);
		
		void randomiseShipPositions(void);				// randomly set the ship positions in the shipArray through the cells (does NOT write to the cellArray but random positions are assigned so as to avoid collisions)
		bool placeShipsInCellArray(void);				// places ships in the shipArray into the CellArray (checks that the position of the ships do not collide) (returns true on success)
		bool placeBufferShipsInBufferCellArray(void);	// " ditto " for the atomArrayBuffer and cellArrayBuffer
		void clearCellArrayBuffer(void);
		void swapArrayBuffers(void);					// swap ptr's to cellArray and cellArrayBuffer, shipArray and shipArrayBuffer
		
		bool placeBufferShipInBufferCellArray(long shipArrayIndex); // place a single Ship from the shipArrayBuffer in the cellArrayBuffer (its position is read from the ship's position data member, not passed in as a parameter)
		
		bool update(void);								// tries to do what the ship's controller has requested for a single time step (return false at game-over, else return true)
		
		void randomiseGoldPositions(void);
		bool placeGoldsInCellArrayAndCellArrayBuffer(void);			// places gold in the goldArray into the CellArray and CellArrayBuffer (checks that the position of the gold does not collide) (returns true on success)
		
		void display(void);								// Methods to display what is described in the method name
		void displayShipsInSea(void);					// display the ships
		void displayGoldsInSea(void);					// etc....
		void displayCannonPath(void);
		void displayRocksInSea(void);
		void displayWrecksInSea(void);
		
		bool attemptShipMoveAhead(long shipArrayIndex);			// Methods to attempt to do each of the actions requested by the ship's controllers
		bool attemptShipCollectGold(long shipArrayIndex);
		bool attemptShipTurn(long shipArrayIndex, Globals::ShipAction requestedAction);
		bool attemptShipFireCannonAhead(long shipArrayIndex);
		bool attemptShipPass(long shipArrayIndex);
		
		bool cellArrayBufferIsOccupiedByShip(long xIndex, long yIndex) const;	// Methods to check the future state to see if a collision will occur
		bool cellArrayBufferIsOccupiedByRock(long xIndex, long yIndex) const;
		
		bool cellArrayIsOccupiedByShip(long xIndex, long yIndex) const;			// Methods to check the current state to see if a collision will occur
		bool cellArrayIsOccupiedByRock(long xIndex, long yIndex) const;
		
		bool cellArrayIsOccupiedByGoldMarker(long xIndex, long yIndex) const;	// check for a *marker* (not to see if there is actually gold at the marker)
		
		long getCellArrayDimension(void) const;									// number of cells across the array
		double getCellDimension(void) const;									// individual grid cell's 1/(double)cellArrayDimension
		long wrapAroundIndexByDimension(long index) const;						// wraps a cell index that is outside the valid range back into it using torus world edge rules
		SimpleVector getCellPosition(long xIndex, long yIndex) const;					// get the x/y coordinates of a grid cell
		
		long getNeighbourIndex(long shipIndex, Globals::NeighbourDirection location);	// get the cell index of a cell that neighbours another in specified direction
		
		long getRandomShipIndex(long randomIndexIndex);							// return a random ship index from the shuffled array of indices
		void shuffleRandomShipIndexArray(void);									// shuffle the array of randomised ship indices
		
		void debugOutput(std::ostream& outStream);					// human readable
		void fileOutput(std::ofstream& outFile);						// machine readable
		void fileInput(std::ifstream& inFile);						// machine readable
		
		void outputSeaStatistics(long numShips);							// human readable
		void computeAndOutputShipStatistics(long curFrame, bool mute);		// human readable
		void computeAndOutputShipStatisticsGameOver(long curFrame);			// human readable
};

#endif
